package com.yunliuchain.examination.common.service.impl;


import com.yunliuchain.examination.common.bean.*;
import com.yunliuchain.examination.common.config.YunBanDanProperties;
import com.yunliuchain.examination.common.service.FileUploadService;
import com.yunliuchain.examination.common.utils.ImageScale;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author 朱周城
 * @version 1.0
 * @date 2014年5月29日下午1:39:29
 */
@Service
public class FileUploadServiceImpl implements FileUploadService
{
	private Logger log = LoggerFactory.getLogger(FileUploadServiceImpl.class);
	@Autowired
	private ImageConfig imageConfig;

	@Autowired
	private YunBanDanProperties yhgProperties;


	public boolean checkDirType(String dirTypeName)
	{
		return DirConfig.DirType.valueOf(dirTypeName)!=null;
	}
	
	public boolean checkDir(String dirName)
	{
		return imageConfig.checkFileType(dirName);
	}
	
	public ImageConfig getUploadConfigure()
	{
		return imageConfig;
	}
	
	public List<FileMeta> upload(HttpServletRequest request) throws IllegalStateException, IOException
	{

		//保存文件夹类型的名称
//		String dirTypeName = getDirTypeName(request);
		//保存文件夹的名称
		String dirName = getDirName(request);
		//图片保存路径
		String filePath = createFilePath(dirName);
		//上传文件根目录
		String uploadPath = yhgProperties.getAppPicPath() + filePath;
		String uploadUrl = filePath;
		List<FileMeta> files = null;
		files = uploadFile(request, uploadPath, uploadUrl, dirName);
		return files;
	}


	private String createFilePath(String dirName) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String ymd = sdf.format(new Date());
		// 创建文件夹
		String filePath = new StringBuffer("/").append(dirName).append("/").append(ymd).append("/").toString();
		return filePath;
	}
	
	public boolean deleteUploadFile(HttpServletRequest request, String filePath) {
		boolean flag = false;
		String uploadPath = yhgProperties.getAppPicPath();

		String fullPath = new StringBuffer().append(uploadPath).append(filePath).toString();
		
		File file = new File(fullPath);  
	    // 判断目录或文件是否存在  
	    if (!file.exists()) {  // 不存在返回 false  
	        return flag;  
	    } else {  
	        // 判断是否为文件  
	    	if (file.isFile() && file.exists()) {  
	            file.delete();  
	            flag = true;  
	        }  
	    } 
	    return flag;
	}
	
	private String getDirTypeName(HttpServletRequest request)
	{
		String dirType = request.getParameter("dirType");
		log.info("上传目录类型名称:"+dirType);
		if (StringUtils.isBlank(dirType))
		{
			dirType = "files";
		}
		if (!checkDirType(dirType))
		{
			throw new RuntimeException("目录名不正确");
		}
		return dirType;
	}

	private String getDirName(HttpServletRequest request)
	{
		String dir = request.getParameter("dir");
		log.info("上传目录目录:"+dir);
		if (StringUtils.isBlank(dir))
		{
			dir = "image";
		}
		if (!checkDir(dir))
		{
			throw new RuntimeException("目录名不正确");
		}
		return dir;
	}

	
	private List<FileMeta> uploadFile(HttpServletRequest request, String savePath, String saveUrl, String dirName) throws IllegalStateException, IOException 
	{
		ImageConfig.FileType dir = ImageConfig.FileType.valueOf(dirName);
		String saveDir = savePath;
		File dirFile = new File(saveDir);
		if (!dirFile.exists())
		{
			dirFile.mkdirs();
		}
		List<FileMeta> files = null;
		if (true){
			files = new ArrayList<FileMeta>();
			MultipartHttpServletRequest mhr = (MultipartHttpServletRequest) request;
			Iterator<String> it = mhr.getFileNames();
			
			FileConfig fileConf = imageConfig.getFileConfigure(dir);
			String extName = null;
			String newFileName = null;
			String sourceName = null;
			File newFile = null;
			boolean cut = Boolean.valueOf(request.getParameter("cut"));
			while (it.hasNext())
			{
				final MultipartFile mf = mhr.getFile(it.next()); 
				// 检查文件大小
				if (mf.getSize() > fileConf.getMaxSize())
				{
					throw new RuntimeException("上传文件大小超过限制");
				}
				
				// 检查扩展名
				extName = getExtName(mf.getOriginalFilename());
				if (!Arrays.<String> asList(fileConf.getType().split(",")).contains(extName))
				{
					throw new RuntimeException("上传文件扩展名" + extName + "是不允许的扩展名。\n只允许" + fileConf.getType() + "格式。");
				}
				newFileName = createFileName();
				sourceName = newFileName + "."+extName;
				newFile = new File(saveDir,sourceName);
				mf.transferTo(newFile);
				//只有图片才能剪切
				if (cut && (ImageConfig.FileType.product.equals(dir) || ImageConfig.FileType.image.equals(dir)))
				{
					new Thread(new ImageJob(newFile ,savePath, saveDir, newFileName)).start();
				}
				FileMeta fileMeta = new FileMeta();
	            fileMeta.setFileName(mf.getOriginalFilename());
	            fileMeta.setFileSize(mf.getSize()/1024+" Kb");
	            fileMeta.setFileType(mf.getContentType());
	            fileMeta.setUrl(saveUrl+sourceName);
				files.add(fileMeta);
			}
		}
		return files;
	}



	public static String createFileName(String fileExt)
	{
		StringBuffer sb = buildFileName();
		sb.append(".").append(fileExt);
		return sb.toString();
	}

	private static StringBuffer buildFileName()
	{
		SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
		int num = new Random().nextInt(1000);
		String date = df.format(new Date());
		StringBuffer sb =  new StringBuffer(date).append("_" ).append(num);
		return sb;
	}

	public static String createFileName()
	{
		return buildFileName().toString();
	}

	public static String getExtName(String fileName)
	{
		return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
	}
	/*
	 * 新线程剪切图片
	 */
	private  class ImageJob implements Runnable{
		 private String remotePath;
		 private String fileName;
		 private File file;
		 private String saveDir;
		 
		 public ImageJob(File file ,String remotePath, String saveDir, String fileName)
		{
			 this.remotePath = remotePath;
			 this.fileName = fileName;
			 this.file = file;
			 this.saveDir = saveDir;
		}

		@Override
		public void run()
		{
			File large = new File(saveDir, fileName + ImageConfig.LARGE_SUFFIX);
			File medium = new File(saveDir, fileName + ImageConfig.MEDIUM_SUFFIX);
			File thumbnail = new File(saveDir, fileName + ImageConfig.THUMBNAIL_SUFFIX);
			cutImage(file,new CutConfig(thumbnail, ImageConfig.THUMBNAIL_WIDTH, ImageConfig.THUMBNAIL_HEIGHT), new CutConfig(large, ImageConfig.LARGE_WIDTH, ImageConfig.LARGE_HEIGHT),new CutConfig(medium,ImageConfig.MEDIUM_WIDTH, ImageConfig.MEDIUM_HEIGHT));
		}
		
		private void cutImage(File source, CutConfig...configs){
			
			try
			{
				ImageScale is = new ImageScale();
				BufferedImage sourceImage = ImageIO.read(source);
				FileOutputStream out = null;
				BufferedImage targetImage = null;
				for (CutConfig cutConfig : configs)
				{
					try
					{
						out = new FileOutputStream(cutConfig.getOutFile());
						//只有原图尺寸大于要裁剪的尺寸时,才会进行裁剪,否则就复制原图
						if(sourceImage.getWidth()> cutConfig.getWidth() &&  sourceImage.getHeight() > cutConfig.getHeight()){
							targetImage = is.imageZoomOut(sourceImage, cutConfig.getWidth(), cutConfig.getHeight(), true);
							ImageIO.write(targetImage, "jpeg", out);
						}else{
							IOUtils.copy(new FileInputStream(source), out);
						}
						out.flush();
				        out.close();
					} finally
					{
						if (out != null)
						{
							out.close();
						}
					}
				}
				
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	 }

	

	public List<Map<String, Object>> getFileList(File currentPathFile)
	{
		List<Map<String, Object>> fileList = new ArrayList<Map<String, Object>>();
		if (currentPathFile.listFiles() != null)
		{
			for (File file : currentPathFile.listFiles())
			{
				Map<String, Object> hash = new Hashtable<String, Object>();
				String fileName = file.getName();
				if (file.isDirectory())
				{
					hash.put("is_dir", true);
					hash.put("has_file", (file.listFiles() != null));
					hash.put("filesize", 0L);
					hash.put("is_photo", false);
					hash.put("filetype", "");
				} else if (file.isFile())
				{
					String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
					hash.put("is_dir", false);
					hash.put("has_file", false);
					hash.put("filesize", file.length());
					hash.put("is_photo", Arrays.<String> asList(imageConfig.getImage().getType().split(",")).contains(fileExt));
					hash.put("filetype", fileExt);
				}
				hash.put("filename", fileName);
				hash.put("datetime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(file.lastModified()));
				fileList.add(hash);
			}
		}

		return fileList;
	}

	/**
	 * 按名称排序
	 * 
	 * @author 朱周城
	 * @date 2014年5月29日
	 */
	class NameComparator implements Comparator<Map<String, Object>>
	{
		public int compare(Map<String, Object> a, Map<String, Object> b)
		{
			Boolean a_is_dir = (Boolean) a.get("is_dir");
			Boolean b_is_dir = (Boolean) b.get("is_dir");

			if (a_is_dir && !b_is_dir)
			{
				return -1;
			} else if (!a_is_dir && b_is_dir)
			{
				return 1;
			} else
			{
				return ((String) a.get("filename")).compareTo((String) b.get("filename"));
			}
		}
	}

	/**
	 * 按大小排序
	 * 
	 * @author 朱周城
	 * @date 2014年5月29日
	 */
	class SizeComparator implements Comparator<Map<String, Object>>
	{
		public int compare(Map<String, Object> a, Map<String, Object> b)
		{
			Boolean a_is_dir = (Boolean) a.get("is_dir");
			Boolean b_is_dir = (Boolean) b.get("is_dir");
			Long a_file_size = (Long) a.get("filesize");
			Long b_file_size = (Long) b.get("filesize");

			if (a_is_dir && !b_is_dir)
			{
				return -1;
			} else if (!a_is_dir && b_is_dir)
			{
				return 1;
			} else
			{
				if (a_file_size > b_file_size)
				{
					return 1;
				} else if (a_file_size < b_file_size)
				{
					return -1;
				} else
				{
					return 0;
				}
			}
		}
	}

	/**
	 * 按类型排序
	 * 
	 * @author 朱周城
	 * @date 2014年5月29日
	 */
	class TypeComparator implements Comparator<Map<String, Object>>
	{
		public int compare(Map<String, Object> a, Map<String, Object> b)
		{
			Boolean a_is_dir = (Boolean) a.get("is_dir");
			Boolean b_is_dir = (Boolean) b.get("is_dir");
			if (a_is_dir && !b_is_dir)
			{
				return -1;
			} else if (!a_is_dir && b_is_dir)
			{
				return 1;
			} else
			{
				return ((String) a.get("filetype")).compareTo((String) b.get("filetype"));
			}
		}
	}

	public void sortFile(List<Map<String, Object>> fileList, String order)
	{
		if ("size".equals(order))
		{
			Collections.sort(fileList, new SizeComparator());
		} else if ("type".equals(order))
		{
			Collections.sort(fileList, new TypeComparator());
		} else
		{
			Collections.sort(fileList, new NameComparator());
		}

	}


}
